package belf.migrate.evaluate.helper;

import belf.migrate.api.job.Job;
import belf.migrate.api.taskconf.JobContext;
import belf.migrate.api.type.DbObjectType;
import belf.migrate.api.util.DatabaseType;
import belf.migrate.evaluate.model.*;
import belf.migrate.evaluate.model.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import java.util.HashMap;
import java.util.Map;

import static belf.migrate.api.job.JobCode.FAILTURE;


@Slf4j
public class EvaluateObjectsTool {

    private EvaluateTableTool evaluateTableTool;

    private EvaluateViewTool evaluateViewTool;

    private EvaluateProcedureTool evaluateProcedureTool;

    private EvaluateTriggerTool evaluateTriggerTool;

    private EvaluateTypeTool evaluateTypeTool;

    private EvaluateIndexTool evaluateIndexTool;

    private EvaluateSeqTool evaluateSeqTool;

    private EvaluateSynonymTool evaluateSynonymTool;

    private EvaluateFunctionTool evaluateFunctionTool;

    private DatabaseType sourceDatabaseType;

    private int allSize = 0;
    private int compatibleSize = 0;
    private int convertSize = 0;
    private int unCompatibleSize = 0;
    private int unKnownSize = 0;

    private EvaluateSinkResult sinkResult;

    private Map<String, EvaluateSinkResult> sinkResultMap;

    public EvaluateObjectsTool(JobContext jobContext, Job job) {
        this.evaluateTableTool = new EvaluateTableTool(jobContext, job);
        this.evaluateViewTool = new EvaluateViewTool(jobContext, job);
        this.evaluateProcedureTool = new EvaluateProcedureTool(jobContext, job);
        this.evaluateTriggerTool = new EvaluateTriggerTool(jobContext, job);
        this.evaluateTypeTool = new EvaluateTypeTool(jobContext, job);
        this.evaluateIndexTool = new EvaluateIndexTool(jobContext, job);
        this.evaluateSeqTool = new EvaluateSeqTool(jobContext, job);
        this.evaluateSynonymTool = new EvaluateSynonymTool(jobContext, job);
        this.evaluateFunctionTool = new EvaluateFunctionTool(jobContext, job);
        this.sourceDatabaseType = DatabaseType.getDatabaseType(job.getTask().getTaskConf().getSourceConf().getCatalogName());
        this.sinkResultMap = new HashMap<>();
    }

    public EvaluateObjectsResult run() {
        EvaluateObjectsResult evaluateObjectsResult = new EvaluateObjectsResult();
        // 汇总表的兼容信息
        if (sourceDatabaseType.getObjectTypes().contains(DbObjectType.TABLE)) {
            EvaluateTableResult tableResult = evaluateTableTool.run();
            if (tableResult != null) {
                process(tableResult, evaluateObjectsResult);
            }
            evaluateObjectsResult.setTableResult(tableResult);
        }
        // 汇总视图的兼容信息
        if (sourceDatabaseType.getObjectTypes().contains(DbObjectType.VIEW)) {
            EvaluateViewResult viewResult = evaluateViewTool.run();
            if (viewResult != null) {
                if (!CollectionUtils.isEmpty(viewResult.getNotSupportCatalogs())) {
                    for (String notSupportCatalog : viewResult.getNotSupportCatalogs()) {
                        evaluateObjectsResult.addNoSupportObTypes(notSupportCatalog, DbObjectType.VIEW);
                    }
                }
                process(viewResult, evaluateObjectsResult);

            }
            evaluateObjectsResult.setViewResult(viewResult);
        }
        // 汇总存储过程的兼容信息
        if (sourceDatabaseType.getObjectTypes().contains(DbObjectType.PROCEDURE)) {
            EvaluateProcedureResult procedureResult = evaluateProcedureTool.run();
            if (procedureResult != null) {
                if (!CollectionUtils.isEmpty(procedureResult.getNotSupportCatalogs())) {
                    for (String notSupportCatalog : procedureResult.getNotSupportCatalogs()) {
                        evaluateObjectsResult.addNoSupportObTypes(notSupportCatalog, DbObjectType.PROCEDURE);
                    }
                }
                process(procedureResult, evaluateObjectsResult);

            }
            evaluateObjectsResult.setProcedureResult(procedureResult);
        }
        // 汇总触发器的兼容信息
        if (sourceDatabaseType.getObjectTypes().contains(DbObjectType.TRIGGER)) {
            EvaluateTriggerResult triggerResult = evaluateTriggerTool.run();
            if (triggerResult != null) {
                if (!CollectionUtils.isEmpty(triggerResult.getNotSupportCatalogs())) {
                    for (String notSupportCatalog : triggerResult.getNotSupportCatalogs()) {
                        evaluateObjectsResult.addNoSupportObTypes(notSupportCatalog, DbObjectType.TRIGGER);
                    }
                }
                process(triggerResult, evaluateObjectsResult);
            }
            evaluateObjectsResult.setTriggerResult(triggerResult);
        }
        // 汇总类型兼容信息
        if (sourceDatabaseType.getObjectTypes().contains(DbObjectType.TYPE)) {
            EvaluateTypeResult typeResult = evaluateTypeTool.run();
            if (typeResult != null) {
                if (!CollectionUtils.isEmpty(typeResult.getNotSupportCatalogs())) {
                    for (String notSupportCatalog : typeResult.getNotSupportCatalogs()) {
                        evaluateObjectsResult.addNoSupportObTypes(notSupportCatalog, DbObjectType.TYPE);
                    }
                }
                process(typeResult, evaluateObjectsResult);

            }
            evaluateObjectsResult.setTypeResult(typeResult);
        }
        // 汇总索引兼容信息
        if (sourceDatabaseType.getObjectTypes().contains(DbObjectType.INDEX)) {
            EvaluateIndexResult indexResult = evaluateIndexTool.run();
            if (indexResult != null) {
                if (!CollectionUtils.isEmpty(indexResult.getNotSupportCatalogs())) {
                    for (String notSupportCatalog : indexResult.getNotSupportCatalogs()) {
                        evaluateObjectsResult.addNoSupportObTypes(notSupportCatalog, DbObjectType.INDEX);
                    }
                }
                process(indexResult, evaluateObjectsResult);

            }
            evaluateObjectsResult.setIndexResult(indexResult);
        }
        // 汇总序列兼容信息
        if (sourceDatabaseType.getObjectTypes().contains(DbObjectType.SEQUENCE)) {
            EvaluateSeqResult seqResult = evaluateSeqTool.run();
            if (seqResult != null) {
                if (!CollectionUtils.isEmpty(seqResult.getNotSupportCatalogs())) {
                    for (String notSupportCatalog : seqResult.getNotSupportCatalogs()) {
                        evaluateObjectsResult.addNoSupportObTypes(notSupportCatalog, DbObjectType.SEQUENCE);
                    }
                }
                process(seqResult, evaluateObjectsResult);

            }
            evaluateObjectsResult.setSeqResult(seqResult);
        }
        // 汇总同义词兼容信息
        if (sourceDatabaseType.getObjectTypes().contains(DbObjectType.SYNONYM)) {
            EvaluateSynonymResult synonymResult = evaluateSynonymTool.run();
            if (synonymResult != null) {
                if (!CollectionUtils.isEmpty(synonymResult.getNotSupportCatalogs())) {
                    for (String notSupportCatalog : synonymResult.getNotSupportCatalogs()) {
                        evaluateObjectsResult.addNoSupportObTypes(notSupportCatalog, DbObjectType.SYNONYM);
                    }
                }
                process(synonymResult, evaluateObjectsResult);

            }
            evaluateObjectsResult.setSynonymResult(synonymResult);
        }
        // 汇总函数兼容信息
        if (sourceDatabaseType.getObjectTypes().contains(DbObjectType.FUNCTION)) {
            EvaluateFunctionResult functionResult = evaluateFunctionTool.run();
            if (functionResult != null) {
                if (!CollectionUtils.isEmpty(functionResult.getNotSupportCatalogs())) {
                    for (String notSupportCatalog : functionResult.getNotSupportCatalogs()) {
                        evaluateObjectsResult.addNoSupportObTypes(notSupportCatalog, DbObjectType.FUNCTION);
                    }
                }
                process(functionResult, evaluateObjectsResult);

            }
            evaluateObjectsResult.setFunctionResult(functionResult);
        }

        evaluateObjectsResult.setSinkStatisticsMap(sinkResultMap);
        return evaluateObjectsResult;
    }

    private void process(EvaluateBaseResult baseResult, EvaluateObjectsResult evaluateObjectsResult) {
        allSize += baseResult.getAllObjectSize();

        for (String key : baseResult.getSinkStatisticsMap().keySet()) {
            EvaluateSinkResult evaluateSinkResult = getSinkResultList(sinkResultMap, key);
            evaluateSinkResult.addCompatibleSizeByCount(baseResult.getSinkStatisticsMap().get(key).getCompatibleSize(), allSize);
            evaluateSinkResult.addConvertSizeByCount(baseResult.getSinkStatisticsMap().get(key).getConvertSize(), allSize);
            evaluateSinkResult.addUnCompatibleSizeByCount(baseResult.getSinkStatisticsMap().get(key).getUnCompatibleSize(), allSize);
            evaluateSinkResult.addUnKnownSizeByCount(baseResult.getSinkStatisticsMap().get(key).getUnKnownSize(), allSize);
            this.sinkResultMap.put(key, evaluateSinkResult);
        }
        if (FAILTURE == baseResult.getCode()) {
            evaluateObjectsResult.setCode(FAILTURE);
        }

        if (baseResult instanceof EvaluateIndexResult) {
            evaluateObjectsResult.addIndexRisk(baseResult.getIndexRisk());
        }
        evaluateObjectsResult.addAllGrammarType(baseResult.getGrammarTypes());
        evaluateObjectsResult.addColumnRisk(baseResult.getColumnRisk());
        evaluateObjectsResult.addFunctionRisk(baseResult.getFunctionRisk());
    }

    public EvaluateSinkResult getSinkResultList(Map<String, EvaluateSinkResult> sinkResultMap, String key) {
        if (sinkResultMap.containsKey(key)) {
            return sinkResultMap.get(key);
        } else {
            return new EvaluateSinkResult();
        }
    }
}
